#!/usr/bin/python3
import gc
import os
import json
import requests

from openpyxl import load_workbook

from .Base_Plugin import Base_Plugin
from utils import String_Util


class Lookup_Type:
    def __init__(self, entity, lookups) -> None:
        self.entity = entity
        self.lookups = lookups

    def code_lookups(self):
        lookupJson = {"zh_cn": {}, "en": {}}
        for lookup in self.lookups:
            cn = []
            en = []
            for item in self.lookups[lookup]:
                cn.append(f"""{item["cn"]}~{item["code"]}""")
                en.append(f"""{item["en"]}~{item["code"]}""")
            lookupJson["zh_cn"][lookup] = ",".join(cn)
            lookupJson["en"][lookup] = ",".join(en)
        return json.dumps(lookupJson, ensure_ascii=False, indent=4)

    def code(self):
        author = self.entity.author
        package = self.entity.package
        lookups = self.code_lookups()
        return f"""{lookups}
"""

    def save_file(self, dir):
        _target_dir = os.path.join(dir, "0")
        if not os.path.exists(_target_dir):
            os.makedirs(_target_dir)
        with open(
            os.path.join(_target_dir, "lookupType.json"),
            mode="w",
            encoding="utf-8",
        ) as f:
            f.write(self.code())


class Lookup_Item:
    def __init__(self, entity, lookups) -> None:
        self.entity = entity
        self.lookups = lookups

    def code_lookups(self):
        lookupJson = {"zh_cn": {}, "en": {}}
        for lookup in self.lookups:
            for item in self.lookups[lookup]:
                code = item["code"]
                lookupJson["zh_cn"][code] = item["cn"]
                lookupJson["en"][code] = item["en"]
        return json.dumps(lookupJson, ensure_ascii=False, indent=4)

    def code(self):
        author = self.entity.author
        package = self.entity.package
        lookups = self.code_lookups()
        return f"""{lookups}
"""

    def save_file(self, dir):
        _target_dir = os.path.join(dir, "0")
        if not os.path.exists(_target_dir):
            os.makedirs(_target_dir)
        with open(
            os.path.join(_target_dir, "lookupItem.json"),
            mode="w",
            encoding="utf-8",
        ) as f:
            f.write(self.code())


class Lookup:
    def __init__(self, lookup_type: Lookup_Type, lookup_item: Lookup_Item):
        self.lookup_type = lookup_type
        self.lookup_item = lookup_item

    def code(self):
        lookup_type = self.lookup_type.code()
        lookup_item = self.lookup_item.code()
        return f"""const LookupTypeResource = {lookup_type}
const LookupItemResource = {lookup_item}"""

    def save_file(self, dir):
        _target_dir = os.path.join(dir, "0")
        if not os.path.exists(_target_dir):
            os.makedirs(_target_dir)
        with open(
            os.path.join(_target_dir, "lookup.js"),
            mode="w",
            encoding="utf-8",
        ) as f:
            f.write(self.code())


class API:

    def __init__(self, entities, api_prefix) -> None:
        self.openApi = "https://ccaxx.w7sell.cn/dev/gemstone/v3/api-docs?group=%E5%AE%9D%E7%9F%B3%E4%BE%9B%E5%BA%94%E5%B9%B3%E5%8F%B0"
        self.entities = entities
        self.api_prefix = api_prefix
        self.prefix = "$base"
        self.name_mapping = {
            "add": "insert",
            "deleteByIds": "del",
            "updateById": "update",
            "nullifyOrRevertByIds": "status",
            "swap": "swap",
            "findById": "get",
            "findPage": "page",
            "getNextSortNumber": "sort",
            "exists": "exists",
            "listByCondition": "list",
        }

    def get_module(self, content):
        name = String_Util.middle_line_to_camel(content.split("/")[3])
        return name[:1].lower() + name[1:]

    def set_base(self, content, obj):
        obj["base"] = "/" + "/".join(content.split("/")[1:4])

    def set_comment(self, obj, _path):
        if "post" in _path:
            item = _path["post"]
        elif "get" in _path:
            item = _path["get"]
        obj["comment"] = item["tags"][0]

    def set_attr(self, content, obj):
        if "api" not in content:
            return
        name = content.split("/")[4]
        if name in self.name_mapping:
            _key = self.name_mapping[name]
        else:
            _key = name
        obj[String_Util.field_name(String_Util.middle_line_to_camel(_key))] = (
            f"""{self.prefix}/{content.split("/")[4]}"""
        )

    def get_module_api_code(self, api):
        code_list = []
        for module in api:
            obj = api[module]
            attr_codes = []
            for k in api[module]:
                if "comment" in k:
                    continue
                attr_codes.append(
                    f"""
      {k}: "{obj[k]}","""
                )
            code_list.append(
                f"""\t// {obj['comment']}
    {module}: {"{"}{"".join(attr_codes)}
    {"},"}
"""
            )
        return "".join(code_list)

    def code_api(self):
        response = requests.get(self.openApi)
        data = response.json()
        _api = {}
        for k in data["paths"]:
            if not k.startswith(self.api_prefix):
                continue
            module = self.get_module(k)
            if module not in _api:
                _api[module] = {}
            if "base" not in _api[module]:
                self.set_base(k, _api[module])
            if "comment" not in _api[module]:
                self.set_comment(_api[module], data["paths"][k])
            self.set_attr(k, _api[module])
        return self.get_module_api_code(_api)

    def code(self):
        code_api = self.code_api()
        return f"""(() => {"{"}
  API = {"{"}
  {code_api}  {"}"};
{"}"})();
"""

    def save_file(self, dir):
        _target_dir = os.path.join(dir, "0")
        if not os.path.exists(_target_dir):
            os.makedirs(_target_dir)
        with open(
            os.path.join(_target_dir, "api.js"),
            mode="w",
            encoding="utf-8",
        ) as f:
            f.write(self.code())


class Entity:

    def __init__(self, author, package, table_name: str, comment: str) -> None:
        self.author = author
        self.package = package
        self.table_name = table_name
        self.name = String_Util.entity_name(self.table_name)
        self.comment = String_Util.check_comment_symbol(comment)
        self.fields = list()
        self.prefix = self.table_name.split("_")[0].lower()
        self.sort_number = False


class Generate_Web_Code(Base_Plugin):
    """生成前端代码插件"""

    def __init__(self, context) -> None:
        super().__init__()
        self.context = context
        self.api_prefix = self.context["code_config"]["web"]["api"]["prefix"]

    def get_lookups(self, _lookup_type, _lookup_item):
        lookup_type_dict = dict()
        lookups = dict()
        for row in _lookup_type.rows:
            if row[0].row < self.project_config["通用开始行"] or row[3].value != "Y":
                continue
            code = row[0].value
            if code is None:
                break
            name = row[1].value
            lookups[code] = list()
            lookup_type_dict[code] = name

        for row in _lookup_item.rows:
            if row[0].row < self.project_config["通用开始行"] or row[5].value != "Y":
                continue
            code = row[0].value
            if code is None:
                break
            if code in lookup_type_dict:
                lookups[code].append(
                    {
                        "code": row[1].value,
                        "description": "{}:{}".format(
                            lookup_type_dict[code], row[2].value
                        ),
                        "cn": row[2].value,
                        "en": row[3].value,
                    }
                )
        return lookups

    def run(self, workspace, source):
        author = self.context["author"]
        package = self.context["package"]
        workbook = load_workbook(os.path.join(workspace, source))
        _directory = workbook["目录"]
        _lookup_type = workbook["数据字典组"]
        _lookup_item = workbook["数据字典项"]
        lookups = self.get_lookups(_lookup_type, _lookup_item)

        _target_path = os.path.join(workspace, self.context["code_target"])
        if not os.path.exists(_target_path):
            os.mkdir(_target_path)

        _entities = list()
        for row in _directory.rows:
            if row[0].value == "序号":
                continue
            if row[1].value is None:
                break

            entity = Entity(author, package, row[1].value, row[2].value)
            _entities.append(entity)
            self.processed += 1

        try:
            api = API(_entities, self.api_prefix)
            api.save_file(_target_path)
            lookup_type = Lookup_Type(entity, lookups)
            lookup_item = Lookup_Item(entity, lookups)
            lookup = Lookup(lookup_type, lookup_item)
            lookup.save_file(_target_path)
        except:
            self.print(f"""未成功连接{api.openApi},前端API代码生成已跳过""")
        del workbook
        gc.collect()
        return source
